package com.bzb.secure.store.plugin

import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.text.TextUtils
import java.io.ByteArrayOutputStream
import java.security.KeyFactory
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.KeyStore.PrivateKeyEntry
import java.security.KeyStore.ProtectionParameter
import java.security.KeyStore.SecretKeyEntry
import java.security.KeyStoreException
import java.security.PublicKey
import java.security.Signature
import java.security.interfaces.RSAPublicKey
import java.security.spec.X509EncodedKeySpec
import java.util.Enumeration
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec


/**
 * KeyStore密钥管理
 */
object KeyStoreManager {
    private lateinit var keyStore: KeyStore
    private const val CIPHER_TRANSFORMATION = "RSA/ECB/PKCS1Padding"
    private const val PROVIDER = "AndroidKeyStore"
    private const val MAX_DECRYPT_BLOCK = 128 // 根据秘钥长度计算得出
    private const val MAX_ENCRYPT_BLOCK = 117 // 根据秘钥长度计算得出

    init {
        init()
    }

    private fun init() {
        try {
            keyStore = KeyStore.getInstance(PROVIDER)
            keyStore.load(null)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 获取当前应用密钥库中的条目
     */
    fun getAliases(): Enumeration<String>? {
        try {
            return keyStore.aliases()
        } catch (e: KeyStoreException) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * ByteArray 转 hexString
     */
    fun toHexString(bytes: ByteArray): String {
        val result = StringBuilder()
        for (aByte in bytes) {
            result.append(String.format("%02x", aByte))
        }
        return result.toString()
    }

    fun ByteArray.toHexStr(): String {
        return joinToString("") { "%02x".format(it) }
    }

    fun String.hexToByteArray(): ByteArray {
        check(length % 2 == 0) { "Must have an even length" }
        val byteIterator = chunkedSequence(2)
            .map { it.toInt(16).toByte() }
            .iterator()
        return ByteArray(length / 2) { byteIterator.next() }
    }

    /**
     * 先判断是否存在该别名
     */
    private fun containsAlias(alias: String?): Boolean {
        if (TextUtils.isEmpty(alias)) {
            return false
        }
        try {
            return keyStore.containsAlias(alias)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 生成新的密钥 AES
     *
     * @param alias 存储在KeyStore中的别名
     */
    fun generateAES(alias: String): ByteArray? {
        if (containsAlias(alias)) {
            println("已存在的 alias: $alias")
            return (keyStore.getKey(alias, null) as SecretKey?)?.encoded
        }
        try {
            val keyGenParameterSpec = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build()
            val generator =
                KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, PROVIDER)
            generator.init(keyGenParameterSpec)
            return generator.generateKey().encoded
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * AES 加密
     */
    fun encryptAES(data: ByteArray, alias: String): ByteArray? {
        try {
            val secretKey = (keyStore.getEntry(alias, null) as SecretKeyEntry?)?.secretKey
            val cipher = Cipher.getInstance("AES/GCM/NoPadding")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)
            val result = cipher.doFinal(data)
            return cipher.doFinal(result)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * AES 解密
     */
    fun decryptAES(data: ByteArray, alias: String, iv: ByteArray): ByteArray? {
        try {
            val secretKey = (keyStore.getEntry(alias, null) as SecretKeyEntry?)?.secretKey
            val cipher = Cipher.getInstance("AES/GCM/NoPadding")
            cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, iv))
            cipher.doFinal(data)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 生成一对用于加解密的公私钥对
     *
     * @param alias 存储在KeyStore中的别名
     * @param keySize 密钥长度, RSA key size must be >= 512 and <= 8192
     * @return 公钥
     */
    fun generateKeyPair(alias: String, keySize: Int): PublicKey? {
        if (containsAlias(alias)) {
            println("已存在的 alias: $alias")
            return keyStore.getCertificate(alias)?.publicKey
        }

        try {
            val keyPairGenerator =
                KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, PROVIDER)
            val spec = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_DECRYPT /*此参数只针对私钥设置*/)
                .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                .setKeySize(keySize)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                .build()
            keyPairGenerator.initialize(spec)
            return keyPairGenerator.generateKeyPair().public
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }


    /**
     * RSA 加密
     *
     * @param alias KeyStore中的别名
     * @param data 要解密的数据
     */
    fun encryptRSA(alias: String, data: ByteArray): ByteArray? {
        try {
            //取出密钥
            val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry
            val publicKey = privateKeyEntry.certificate.publicKey as RSAPublicKey
//            val encoded = publicKey.encoded
//            if (encoded != null) {
//                println("密钥-公钥: ${Base64.encodeToString(encoded, Base64.DEFAULT)}")
//            }
            val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
            cipher.init(Cipher.ENCRYPT_MODE, publicKey)
            return cipher.doFinal(data)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * RSA 解密
     *
     * @param alias KeyStore中的别名
     * @param data 要解密的数据
     */
    fun decryptRSA(alias: String, data: ByteArray): ByteArray? {
        try {
            //取出密钥
            val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry
            val privateKey = privateKeyEntry.privateKey
            val algorithm = privateKey.algorithm
            if (privateKey != null) {
                println("密钥-私钥: 存在, algorithm=$algorithm")
            } else {
                println("密钥-私钥: null, algorithm=$algorithm")
            }
            val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
            cipher.init(Cipher.DECRYPT_MODE, privateKey)
            return cipher.doFinal(data)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 加密后端分段加密的白盒密钥大数据(分段加密)
     */
    @Throws(java.lang.Exception::class)
    fun encryptBigRSA(alias: String, encryptedData: ByteArray): ByteArray? {
        //取出密钥
        val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry

        val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
        cipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.certificate.publicKey)

        val inputLength = encryptedData.size
        var i = 0
        var offSet = 0
        var cache: ByteArray
        // 对数据分段解密
        val out = ByteArrayOutputStream()
        while (inputLength - offSet > 0) {
            cache = if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                cipher.doFinal(encryptedData, offSet, MAX_ENCRYPT_BLOCK)
            } else {
                cipher.doFinal(encryptedData, offSet, inputLength - offSet)
            }
            out.write(cache, 0, cache.size)
            i++
            offSet = i * MAX_ENCRYPT_BLOCK
        }
        val decryptedData = out.toByteArray()
        out.close()
        return decryptedData
    }

    /**
     * 解密后端分段加密的白盒密钥大数据(分段解密)
     */
    @Throws(java.lang.Exception::class)
    fun decryptBigRSA(alias: String, encryptedData: ByteArray): ByteArray? {
        //取出密钥
        val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry

        val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION)
        cipher.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey)

        val inputLength = encryptedData.size
        var i = 0
        var offSet = 0
        var cache: ByteArray
        // 对数据分段解密
        val out = ByteArrayOutputStream()
        while (inputLength - offSet > 0) {
            cache = if (inputLength - offSet > MAX_DECRYPT_BLOCK) {
                cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK)
            } else {
                cipher.doFinal(encryptedData, offSet, inputLength - offSet)
            }
            out.write(cache, 0, cache.size)
            i++
            offSet = i * MAX_DECRYPT_BLOCK
        }
        val decryptedData = out.toByteArray()
        out.close()
        return decryptedData
    }

    fun deleteKey(alias: String?) {
        try {
            keyStore.deleteEntry(alias)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun setEntry(alias: String?, entry: KeyStore.Entry?, protParam: ProtectionParameter?) {
        try {
            keyStore.setEntry(alias, entry, protParam)
        } catch (e: KeyStoreException) {
            e.printStackTrace()
        }
    }

    fun getEntry(alias: String?): KeyStore.Entry? {
        try {
            return keyStore.getEntry(alias, null)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    fun getEntry(alias: String?, protParam: ProtectionParameter?): KeyStore.Entry? {
        try {
            return keyStore.getEntry(alias, protParam)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }


    /**
     * 对数据进行签名
     *
     * @param data
     * @param alias
     */
    fun sign(data: ByteArray?, alias: String?): ByteArray? {
        try {
            //取出密钥
            val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry
            val s = Signature.getInstance("SHA1withRSA")
            s.initSign(privateKeyEntry.privateKey)
            s.update(data)
            return s.sign()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 验证数据签名
     *
     * @param data 原始数据
     * @param signatureData 签署的数据
     * @param alias
     */
    fun verify(data: ByteArray?, signatureData: ByteArray?, alias: String?): Boolean {
        try {
            //取出密钥
            val privateKeyEntry = keyStore.getEntry(alias, null) as PrivateKeyEntry
            val s = Signature.getInstance("SHA1withRSA")
            s.initVerify(privateKeyEntry.certificate)
            s.update(data)
            return s.verify(signatureData)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

}